package com.zyx.lock.service.impl;

import cn.hutool.core.date.DateUtil;
import com.zyx.lock.common.LockConstants;
import com.zyx.lock.factory.DistributedLockFactory;
import com.zyx.lock.service.ITestService;
import com.zyx.lock.utils.DistributedRedisLock;
import org.redisson.api.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.concurrent.TimeUnit;

/**
 * @author Yaxi.Zhang
 * @since 2022/9/10 15:07
 */
@Service
public class TestServiceImpl implements ITestService {
    private final DistributedLockFactory distributedLockFactory;
    private final RedissonClient redissonClient;

    @Autowired
    public TestServiceImpl(DistributedLockFactory distributedLockFactory, RedissonClient redissonClient) {
        this.distributedLockFactory = distributedLockFactory;
        this.redissonClient = redissonClient;
    }

    @Override
    public void testRlock() {
        DistributedRedisLock lock = distributedLockFactory.getRedisLock(LockConstants.LOCK_KEY);
        lock.lock();
        try {
            System.out.println("I'm outer");
            test02();
            try {
                TimeUnit.SECONDS.sleep(25);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        } finally {
            lock.unlock();
        }
    }

    private void test02() {
        DistributedRedisLock lock = distributedLockFactory.getRedisLock(LockConstants.LOCK_KEY);
        lock.lock();
        try {
            System.out.println("I'm inner");
            TimeUnit.SECONDS.sleep(20);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    @Override
    public void testFairLock(Long id) {
        // 使用公平锁时，拿到锁的顺序是按照trylock的时间先后来排序的
        RLock fairLock = redissonClient.getFairLock(LockConstants.FAIR_LOCK);
        // 使用普通的可重入锁则是随机获取锁的
        // RLock fairLock = redissonClient.getLock(LockConstants.FAIR_LOCK);

        fairLock.lock(10, TimeUnit.SECONDS);
        try {
            System.out.println("this is fair lock: " + id);
            TimeUnit.SECONDS.sleep(5);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            fairLock.unlock();
        }
    }

    @Override
    public void testRead() {
        RReadWriteLock rwLock = redissonClient.getReadWriteLock(LockConstants.READ_WRITE_LOCK_KEY);
        rwLock.readLock().lock(10, TimeUnit.SECONDS);

        System.out.println("测试读锁。。。。" + DateUtil.format(LocalDateTime.now(), "yyyy-MM-dd HH:mm:ss"));
    }

    @Override
    public void testWrite() {
        RReadWriteLock rwLock = redissonClient.getReadWriteLock(LockConstants.READ_WRITE_LOCK_KEY);
        rwLock.writeLock().lock(10, TimeUnit.SECONDS);

        System.out.println("测试写锁。。。。" + DateUtil.format(LocalDateTime.now(), "yyyy-MM-dd HH:mm:ss"));
    }

    @Override
    public void testSemaphore() {
        RSemaphore semaphore = redissonClient.getSemaphore(LockConstants.SEMAPHORE_KEY);
        semaphore.trySetPermits(3);
        try {
            semaphore.acquire();
            TimeUnit.SECONDS.sleep(5);
            System.out.println("get semaphore lock:" + DateUtil.format(LocalDateTime.now(), "yyyy-MM-dd HH:mm:ss"));
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            semaphore.release();
        }
    }

    @Override
    public void testLatch() {
        RCountDownLatch latch = this.redissonClient.getCountDownLatch(LockConstants.COUNT_DOWN_KEY);
        latch.trySetCount(6);
        try {
            latch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void testCountDown() {
        RCountDownLatch latch = this.redissonClient.getCountDownLatch(LockConstants.COUNT_DOWN_KEY);
        latch.trySetCount(6);
        latch.countDown();
    }
}
